/******************************************************************************
 * FileName:    gwin_fifo.c
 * Desc:        fifo
 *
 *
 * Author:      Lin
 * Notes:
 *
 ******************************************************************************/

/*-------------------------- Includes ---------------------------------------*/
#include "gwin_fifo.h"


/*-------------------------- Macro Definitions ------------------------------*/
#define GWIN_FIFO_LEN_MIN(a, b)         (((a) < (b)) ? (a) : (b))


/*-------------------------- Type Declarations ------------------------------*/

/*-------------------------- Global Variables -------------------------------*/

/*-------------------------- Local Variables --------------------------------*/

/*-------------------------- Functions Declarations -------------------------*/

/*-------------------------- Functions Definitions --------------------------*/
/**
 * @brief 初始化
 */
uint8_t gwin_fifo_init(gwin_fifo_t *fifo, uint8_t *buf, uint16_t len)
{
    // Check buffer for null pointer.
    if (buf == NULL)
    {
        return 0;
    }

    fifo->buf = buf;
    fifo->size_mask = len - 1;
    fifo->read_pos = 0;
    fifo->write_pos = 0;

    return 1;
}


/**
 * @brief 清
 */
void gwin_fifo_flush(gwin_fifo_t *fifo)
{
    fifo->read_pos = fifo->write_pos;
}

/**
 * @brief 获取数据长度
 */
uint16_t gwin_fifo_length(gwin_fifo_t *fifo)
{
    uint16_t read_pos = fifo->read_pos;
    if (fifo->write_pos >= read_pos)
    {
        return fifo->write_pos - read_pos;
    }
    else
    {
        return fifo->write_pos + (fifo->size_mask + 1 - read_pos);
    }
}

/**
 * @brief 获取剩余长度
 */
uint16_t gwin_fifo_remain(gwin_fifo_t *fifo)
{
    return fifo->size_mask + 1 - gwin_fifo_length(fifo) - 1;        // 剩余长度-1，避免写指针追尾读指针，误判缓存数据长度为0
}

/**
 * @brief 获取写位置
 */
uint8_t *gwin_fifo_get_write_pos(gwin_fifo_t *fifo)
{
    uint16_t write_pos = fifo->write_pos;
    return &fifo->buf[write_pos];
}


/**
 * @brief 读
 */
uint16_t gwin_fifo_read(gwin_fifo_t *fifo, uint8_t *data, uint16_t len)
{
    if (fifo == NULL)
    {
        return 0;
    }

    uint16_t read_size = GWIN_FIFO_LEN_MIN(len, gwin_fifo_length(fifo));

    if (data == NULL)
    {
        fifo->read_pos = (fifo->read_pos + read_size) & fifo->size_mask;
    }
    else
    {
        for (uint16_t i = 0; i < read_size; i++)
        {
            data[i] = fifo->buf[fifo->read_pos];
            fifo->read_pos = (++fifo->read_pos) & fifo->size_mask;
        }
    }

    return read_size;
}

/**
 * @brief 写
 */
uint16_t gwin_fifo_write(gwin_fifo_t *fifo, const uint8_t *data, uint16_t len)
{
    uint16_t remain = gwin_fifo_remain(fifo);

    if (fifo == NULL || data == NULL || remain == 0)
    {
        return 0;
    }

    uint16_t write_size = GWIN_FIFO_LEN_MIN(len, remain);

    for (uint16_t i = 0; i < write_size; i++)
    {
        fifo->buf[fifo->write_pos] = data[i];
        fifo->write_pos = (++fifo->write_pos) & fifo->size_mask;
    }

    return write_size;
}


/*-------------------------- END OF FILE ------------------------------------*/

